﻿using Common.Library;
using Common.Model;
using Container.Library;
using DevOps.Model;
using Encrypt.Library;
using Redis.Library;
using Serialize.Library;
using System;
using System.Collections.Generic;
using System.Linq;
/*
* 命名空间: DevOps.Logic
*
* 功 能： 接口访问监控日志Redis操作类
*
* 类 名： ApiMonitorLogServiceRedis
*
* Version   变更日期            负责人     变更内容
* ─────────────────────────────────────────────────
* V1.0.1    2020/4/10 11:13:35 	Harvey     创建
*
* Copyright (c) 2020 Harvey Corporation. All rights reserved.
*/
namespace DevOps.Logic
{
    /// <summary>
    /// 接口访问监控日志Redis操作类
    /// </summary>
    public class ApiMonitorLogServiceRedis
    {

        #region 访问明细操作

        /// <summary>
        /// 插入接口访问监控日志
        /// </summary>
        /// <param name="apiMonitorLogInfo"></param>
        /// <param name="successAction"></param>
        /// <param name="failAction"></param>
        public static void SaveApiMonitorLog(SafeApiMonitorLogEntity apiMonitorLogInfo, Action successAction = null, Action failAction = null)
        {
            bool result = RedisClient.GetRedisDb(RedisLogInfo.RedisLogDbLog).HashSet(RedisLogInfo.RedisApiMonitorHashId, apiMonitorLogInfo.id, apiMonitorLogInfo);
            if (result)
            {
                successAction?.Invoke();
            }
            else
            {
                failAction?.Invoke();
            }
        }

        /// <summary>
        /// 获取访问监控日志信息
        /// </summary>
        /// <param name="successAction">成功执行</param>
        /// <param name="failAction">失败执行</param>
        /// <returns></returns>
        public static void GetAllApiMonitorLog(Action<List<SafeApiMonitorLogEntity>> successAction = null, Action failAction = null)
        {
            var resultInfo = RedisClient.GetRedisDb(RedisLogInfo.RedisLogDbLog).HashGetAll<SafeApiMonitorLogEntity>(RedisLogInfo.RedisApiMonitorHashId);
            if (resultInfo != null && resultInfo.Count > 0)
            {
                successAction?.Invoke(resultInfo);
            }
            else
            {
                failAction?.Invoke();
            }
        }

        /// <summary>
        /// 批量删除监控日志信息
        /// </summary>
        /// <param name="keys"></param>
        public static void RemoveApiMonitorLog(List<string> keys)
        {
            RedisClient.GetRedisDb(RedisLogInfo.RedisLogDbLog).HashDeletes(RedisLogInfo.RedisApiMonitorHashId, keys);
        }

        /// <summary>
        /// 删除过期接口访问记录信息
        /// </summary>
        public static void RemoveExpiredApiMonitorLog()
        {
            var apiMonitorList = RedisClient.GetRedisDb(RedisLogInfo.RedisLogDbLog).HashGetAll<SafeApiMonitorLogEntity>(RedisLogInfo.RedisApiMonitorHashId);
            if (apiMonitorList.Count > 0)
            {
                DateTime nowTime = DateTime.Now;
                List<string> keys = apiMonitorList.Where(p => p.start_time.AddSeconds(RedisLogInfo.RedisApiMonitorTimeOut) <= nowTime).Select(p => p.id).ToList();
                if (keys.Count > 0)
                {
                    RedisClient.GetRedisDb(RedisLogInfo.RedisLogDbLog).HashDeletes(RedisLogInfo.RedisApiMonitorHashId, keys);

                    #region 删除任务日志记录
                    var apiMonitorLogList = RedisClient.GetRedisDb(RedisCommonInfo.RedisHangfireDbLog).QueueGetList(RedisCommonInfo.RedisHangfireSucceededListId);
                    List<string> hangfirejobList = new List<string>();
                    List<string> hangfirejobHistoryList = new List<string>();
                    List<string> hangfirejobStateList = new List<string>();
                    foreach (var item in apiMonitorLogList)
                    {
                        hangfirejobList.Add(RedisCommonInfo.RedisHangfireJobHashId + item);//hash
                        hangfirejobHistoryList.Add(RedisCommonInfo.RedisHangfireJobHashId + item + ":history");//list
                        hangfirejobStateList.Add(RedisCommonInfo.RedisHangfireJobHashId + item + ":state");//hash
                    }
                    RedisClient.GetRedisDb(RedisCommonInfo.RedisHangfireDbLog).StringKeysDelete(hangfirejobList);
                    RedisClient.GetRedisDb(RedisCommonInfo.RedisHangfireDbLog).StringKeysDelete(hangfirejobHistoryList);
                    RedisClient.GetRedisDb(RedisCommonInfo.RedisHangfireDbLog).StringKeysDelete(hangfirejobStateList);
                    RedisClient.GetRedisDb(RedisCommonInfo.RedisHangfireDbLog).StringKeyDelete(RedisCommonInfo.RedisHangfireSucceededListId);
                    #endregion
                }
            }
        }

        /// <summary>
        /// 清空Hangfire信息
        /// </summary>
        public static void EmptyHangfire()
        {
            RedisClient.GetRedisDb(RedisCommonInfo.RedisHangfireDbLog).Excute("flushdb", null);
        }


        #endregion

        #region 接口访问次数


        /// <summary>
        /// 插入接口访问次数
        /// </summary>
        /// <param name="apiMonitorLogInfo"></param>
        /// <param name="successAction"></param>
        /// <param name="failAction"></param>
        public static void IncrementApiMonitorNumber(SafeApiMonitorLogEntity apiMonitorLogInfo, Action successAction = null, Action failAction = null)
        {

            bool result = RedisClient.GetRedisDb(RedisLogInfo.RedisLogDbLog).HashIncrementAsync(RedisLogInfo.RedisApiMonitorNumberHashId, apiMonitorLogInfo.request_path, 1);

            if (result)
            {
                var apiInfo = JsonHelper.ToJson(apiMonitorLogInfo.MapTo<SafeApiInfoEntity>());
                RedisClient.GetRedisDb(RedisLogInfo.RedisLogDbLog).HashSetIfNotExists(RedisLogInfo.RedisApiHashId, apiMonitorLogInfo.request_path, apiInfo);

                successAction?.Invoke();
            }
            else
            {
                failAction?.Invoke();
            }
        }

        /// <summary>
        /// 获取接口访问次数
        /// </summary>
        /// <param name="successAction">成功执行</param>
        /// <param name="failAction">失败执行</param>
        /// <returns></returns>
        public static void GetApiMonitorNumber(Action<List<SafeApiMonitorNumberEntity>> successAction = null, Action failAction = null)
        {
            List<SafeApiMonitorNumberEntity> safeApiMonitorNumber = new List<SafeApiMonitorNumberEntity>();

            var resultInfo = RedisClient.GetRedisDb(RedisLogInfo.RedisLogDbLog).HashGetAllDic(RedisLogInfo.RedisApiMonitorNumberHashId);

            foreach (var item in resultInfo)
            {
                safeApiMonitorNumber.Add(new SafeApiMonitorNumberEntity()
                {
                    request_path = item.Key,
                    request_number =Convert.ToInt64(item.Value) 
                });
            }
            if (resultInfo != null && resultInfo.Count > 0)
            {
                successAction?.Invoke(safeApiMonitorNumber);
            }
            else
            {
                failAction?.Invoke();
            }
        }

        /// <summary>
        /// 获取接信息
        /// </summary>
        /// <returns></returns>
        public static List<SafeApiInfoEntity> GetApiInfo()
        {
            var resultInfo = RedisClient.GetRedisDb(RedisLogInfo.RedisLogDbLog).HashGetAll<SafeApiInfoEntity>(RedisLogInfo.RedisApiHashId);

            return resultInfo;
        }

        #endregion

        #region 统计与安全操作

        /// <summary>
        /// 插入按照请求路由统计的信息
        /// </summary>
        /// <param name="group"></param>
        public static bool SaveGroup(List<ApiMonitorLogGroup> group)
        {
            bool result = RedisClient.GetRedisDb(RedisLogInfo.RedisLogDbLog).HashSets(RedisLogInfo.RedisApiMonitorStatisticsHashId, group.Select(p => p.id).ToList(), group);

            return result;
        }

        /// <summary>
        /// 获取所有接口请求统计信息
        /// </summary>
        public static List<ApiMonitorLogGroup> GetAllApiMonitorLogGroup()
        {
            var resultInfo = RedisClient.GetRedisDb(RedisLogInfo.RedisLogDbLog).HashGetAll<ApiMonitorLogGroup>(RedisLogInfo.RedisApiMonitorStatisticsHashId);

            return resultInfo;
        }

        /// <summary>
        /// 插入按照请求路由统计的信息
        /// </summary>
        /// <param name="pathGroup"></param>
        public static bool SaveGroupPath(List<ApiMonitorLogPathGroup> pathGroup)
        {
            bool result = RedisClient.GetRedisDb(RedisLogInfo.RedisLogDbLog).HashSets(RedisLogInfo.RedisApiMonitorPathStatisticsHashId, pathGroup.Select(p => p.id).ToList(), pathGroup);

            return result;
        }

        /// <summary>
        /// 获取所有接口请求路由统计信息
        /// </summary>
        public static List<ApiMonitorLogPathGroup> GetAllGroupPath()
        {
            var resultInfo = RedisClient.GetRedisDb(RedisLogInfo.RedisLogDbLog).HashGetAll<ApiMonitorLogPathGroup>(RedisLogInfo.RedisApiMonitorPathStatisticsHashId);

            return resultInfo;
        }


        /// <summary>
        /// 插入按照请求路由和Ip统计的信息
        /// </summary>
        /// <param name="pathIpGroup"></param>
        public static bool SaveGroupPathIp(List<ApiMonitorLogPathIpGroup> pathIpGroup)
        {
            bool result = RedisClient.GetRedisDb(RedisLogInfo.RedisLogDbLog).HashSets(RedisLogInfo.RedisApiMonitorPathIpStatisticsHashId, pathIpGroup.Select(p => p.id).ToList(), pathIpGroup);

            return result;
        }


        /// <summary>
        /// 获取所有按照请求路由和Ip统计的信息
        /// </summary>
        public static List<ApiMonitorLogPathIpGroup> GetAllIpGroupPath()
        {
            var resultInfo = RedisClient.GetRedisDb(RedisLogInfo.RedisLogDbLog).HashGetAll<ApiMonitorLogPathIpGroup>(RedisLogInfo.RedisApiMonitorPathIpStatisticsHashId);

            return resultInfo;
        }



        /// <summary>
        /// 删除过期接口访问记录统计信息
        /// </summary>
        public static void RemoveExpiredGroupInfo()
        {

            //按照请求统计的信息
            var groupList = RedisClient.GetRedisDb(RedisLogInfo.RedisLogDbLog).HashGetAll<ApiMonitorLogGroup>(RedisLogInfo.RedisApiMonitorStatisticsHashId);
            if (groupList.Count > 0)
            {
                DateTime nowTime = DateTime.Now;
                List<string> keys = groupList.Where(p => p.statistics_time.AddSeconds(RedisLogInfo.RedisApiMonitorTimeOut) <= nowTime)
                                    .Select(p => p.id)
                                    .ToList();
                if (keys.Count > 0)
                {
                    RedisClient.GetRedisDb(RedisLogInfo.RedisLogDbLog).HashDeletes(RedisLogInfo.RedisApiMonitorStatisticsHashId, keys);
                }
            }

            //按照请求路由统计的信息
            var groupPathList = RedisClient.GetRedisDb(RedisLogInfo.RedisLogDbLog).HashGetAll<ApiMonitorLogPathGroup>(RedisLogInfo.RedisApiMonitorPathStatisticsHashId);
            if (groupPathList.Count > 0)
            {
                DateTime nowTime = DateTime.Now;
                List<string> keys = groupPathList.Where(p => p.statistics_time.AddSeconds(RedisLogInfo.RedisApiMonitorTimeOut) <= nowTime)
                                    .Select(p => p.id)
                                    .ToList();
                if (keys.Count > 0)
                {
                    RedisClient.GetRedisDb(RedisLogInfo.RedisLogDbLog).HashDeletes(RedisLogInfo.RedisApiMonitorPathStatisticsHashId, keys);
                }
            }

            //按请求路由和Ip统计的信息
            var groupPathIpList = RedisClient.GetRedisDb(RedisLogInfo.RedisLogDbLog).HashGetAll<ApiMonitorLogPathIpGroup>(RedisLogInfo.RedisApiMonitorPathIpStatisticsHashId);
            if (groupPathIpList.Count > 0)
            {
                DateTime nowTime = DateTime.Now;

                List<string> keys = groupPathIpList.Where(p => p.statistics_time.AddSeconds(RedisLogInfo.RedisApiMonitorTimeOut) <= nowTime)
                                    .Select(p => p.id)
                                    .ToList();
                if (keys.Count > 0)
                {
                    RedisClient.GetRedisDb(RedisLogInfo.RedisLogDbLog).HashDeletes(RedisLogInfo.RedisApiMonitorPathIpStatisticsHashId, keys);
                }
            }


        }

        /// <summary>
        /// 插入名单信息
        /// </summary>
        /// <param name="nameList"></param>
        public static bool SaveNameList(ApiMonitorLogNameList nameList)
        {
            //这里是按照请求IP来做Key的，所以在记录中一个Ip对应一条数据。。。有了黑名单，就不会有警告
            bool result = RedisClient.GetRedisDb(RedisLogInfo.RedisLogDbLog).HashSet(RedisLogInfo.RedisApiMonitorNameListHashId, nameList.request_ip, nameList);

            return result;
        }


        /// <summary>
        /// 获取所有名单信息
        /// </summary>
        public static List<ApiMonitorLogNameList> GetAllNameList()
        {
            var resultInfo = RedisClient.GetRedisDb(RedisLogInfo.RedisLogDbLog).HashGetAll<ApiMonitorLogNameList>(RedisLogInfo.RedisApiMonitorNameListHashId);

            return resultInfo;

        }

        /// <summary>
        /// 删除黑名单中某一项
        /// </summary>
        /// <param name="ip"></param>
        /// <returns></returns>
        public static bool RemoveNameList(string ip)
        {
            bool result = RedisClient.GetRedisDb(RedisLogInfo.RedisLogDbLog).HashDelete(RedisLogInfo.RedisApiMonitorNameListHashId, ip);

            return result;
        }
        #endregion

        #region 时间戳防止重放攻击操作

        /// <summary>
        /// 获取对应IP+时间戳的记录
        /// </summary>
        /// <param name="ip">ip</param>
        /// <param name="timestamp">时间戳</param>
        /// <param name="successAction">成功执行</param>
        /// <param name="failAction">失败执行</param>
        /// <returns></returns>
        public static void GetIpTimestamp(string ip, string timestamp, Action<string> successAction = null, Action failAction = null)
        {
            var resultInfo = RedisClient.GetRedisDb(RedisLogInfo.RedisTimestampDbLog).StringGet(RedisLogInfo.RedisApiTimestampId + SecurityHelper.GetMD5Hash(ip + timestamp));
            if (resultInfo.IsNotNullOrEmpty())
            {
                successAction?.Invoke(resultInfo);
            }
            else
            {
                failAction?.Invoke();
            }
        }

        /// <summary>
        /// 插入对应IP+时间戳的记录
        /// </summary>
        /// <param name="ip">ip</param>
        /// <param name="timestamp">时间戳</param>
        /// <param name="successAction">成功执行</param>
        /// <param name="failAction">失败执行</param>
        /// <returns></returns>
        public static void SetIpTimestamp(string ip, string timestamp, Action<bool> successAction = null, Action failAction = null)
        {
            //超时时间5秒
            int timeout = 5;
            string value = SecurityHelper.GetMD5Hash(ip + timestamp);
            var resultInfo = RedisClient.GetRedisDb(RedisLogInfo.RedisTimestampDbLog).StringSet(RedisLogInfo.RedisApiTimestampId + value, value, timeout);
            if (resultInfo)
            {
                successAction?.Invoke(resultInfo);
            }
            else
            {
                failAction?.Invoke();
            }
        }
        #endregion

    }
}


